home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 142 / Gekkan Dennou Club - 2000.3 Vol. 142 (Japan).7z / Gekkan Dennou Club - 2000.3 Vol. 142 (Japan) (Track 1).bin / ikap / etc2 / src.lzh / sound.c < prev    next >
C/C++ Source or Header  |  2000-02-04  |  12KB  |  519 lines

  1. /* sound.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <mbctype.h>
  6. #include <sys/dos.h>
  7. #include <sys/xglob.h>
  8. #include "tr68k.h"
  9. #include "sound.h"
  10. #include "pcm8call.h"
  11. #include "GetPcmPath.h"
  12.  
  13.  
  14. static void *pcm_ptr[TYPE_MAX][TRACK_MAX];    /* 読み込んだ .PCM データへのポインタ */
  15. static char pcm_full_fname[TYPE_MAX][TRACK_MAX][92];    /* .CNF に書かれていたそのままの .PCM ファイル名 */
  16.  
  17. static struct {
  18.     int note_no[TRACK_MAX];    /* 次に書き込む note_no */
  19.     int l_current[TRACK_MAX];    /* 'l' で指定された現在の音長 */
  20.     int volume_current[TRACK_MAX];    /* 現在の音量 */
  21. } zms_analyse;
  22.  
  23.  
  24.  
  25. /* .ZMS ファイル書き込み */
  26. /* 綺麗な.ZMSを生成しようとしたらソースが泥沼になったにょ */
  27. int SoundSaveZms (char *fname)
  28. {
  29.     FILE *fp;
  30.     char note_char[] = "cdef";
  31.     int track, type;
  32.  
  33.     if (fname == NULL)
  34.         fp = fopen ("TEMP.ZMS", "w");
  35.     else
  36.         fp = fopen (fname, "w");
  37.     if (fp == NULL)
  38.         return (-1);
  39.  
  40.     fprintf (fp, ".comment TR-68K\n(i)\n"
  41.     "(m9,2048)(aADPCM,9)(m10,2048)(aADPCM,10)(m11,2048)(aADPCM,11)(m12,2048)(aADPCM,12)\n"
  42.          "(m13,2048)(aADPCM,13)(m14,2048)(aADPCM,14)(m15,2048)(aADPCM,15)(m16,2048)(aADPCM,16)\n\n"
  43.         );
  44.  
  45.     /* .o0c = fname.pcm */
  46.     {
  47.         int pcm_use[TYPE_MAX][TRACK_MAX];    /* .PCM が実際に使用されているか */
  48.         int note_abs;
  49.  
  50.         /* 初期化 */
  51.         for (track = 0; track < TRACK_MAX; track++) {
  52.             for (type = 0; type < TYPE_MAX; type++) {
  53.                 pcm_use[type][track] = 0;
  54.             }
  55.         }
  56.  
  57.         /* 実際に使用されている .PCM を探す */
  58.         for (track = 0; track < TRACK_MAX; track++) {
  59.             for (note_abs = 0; note_abs < bar_max_table[bar_max] * NOTE_DISP; note_abs++) {
  60.                 if (note_volume[track][note_abs])
  61.                     pcm_use[note_type[track][note_abs]][track] = !0;
  62.             }
  63.         }
  64.  
  65.         /* .o0c = fname.pcm を書き込む */
  66.         for (track = 0; track < TRACK_MAX; track++) {
  67.             for (type = 0; type < TYPE_MAX; type++) {
  68.                 if ((pcm_ptr[type][track]) && (pcm_use[type][track]))
  69.                     fprintf (fp, ".o%d%c = %s\n", track, note_char[type], &pcm_full_fname[type][track][0]);
  70.             }
  71.         }
  72.     }
  73.  
  74.     /* テンポを書き込む */
  75.     fprintf (fp, "\n(t9)\tt%d\n\n", VDISP60SEC / 4 / note_tempo);
  76.  
  77.     /* トラックごとに演奏データを書き込む */
  78.     for (track = 0; track < TRACK_MAX; track++) {
  79.         char volume, volume_current;
  80.         int bar_count, note_count, note_count2;        /* 空白や改行を入れるためのカウンタ */
  81.         int note_abs;
  82.  
  83.         fprintf (fp, "(t%d)\to%d l16 v8 @d1\n\(t%d)\t[do]\n", track + 9, track, track + 9);
  84.         volume_current = 8;
  85.  
  86.         bar_count = 0;
  87.         note_count = note_count2 = 0;
  88.         fprintf (fp, "(t%d)\t\t", track + 9);
  89.         for (note_abs = 0; note_abs < bar_max_table[bar_max] * NOTE_DISP; note_abs++) {
  90.             volume = note_volume[track][note_abs];
  91.  
  92.             if (volume) {    /* 音符がある */
  93. #ifdef OPTIMISE_LENGTH
  94.                 int pcm_length;
  95.                 int i;
  96. #endif
  97.                 if (volume != volume_current) {
  98.                     /* 前回との音量差によって分岐 */
  99.                     switch (volume - volume_current) {
  100.                     case 2:
  101.                         fputs ("~~", fp);
  102.                         break;
  103.                     case 1:
  104.                         fputs ("~", fp);
  105.                         break;
  106.                     case -1:
  107.                         fputs ("_", fp);
  108.                         break;
  109.                     case -2:
  110.                         fputs ("__", fp);
  111.                         break;
  112.                     default:
  113.                         fprintf (fp, "v%d", volume);
  114.                         break;
  115.                     }
  116.                     volume_current = volume;
  117.                 }
  118.                 fprintf (fp, "%c", note_char[note_type[track][note_abs]]);
  119. #ifdef OPTIMISE_LENGTH
  120.                 /* 16分音符の.PCMサイズ=7800/55*note_tempo */
  121.                 pcm_length = pcm_size[note_type[track][note_abs]][track] / (7800 / 55 * note_tempo);
  122.                 if (pcm_length > 3)    /* 4分音符以上は鳴らせない */
  123.                     pcm_length = 3;
  124.  
  125.                 /* .PCM の長さが16分音符何個分かで分岐 */
  126.                 /* 8分音符なら「次が休符」である事を調べて'8'を出力とか */
  127.                 /* これによって "cr" でなく "c8" の様に出力できる */
  128.                 for (i = 0; i < pcm_length; i++) {
  129.                     if ((note_abs + i) >= (bar_max_table[bar_max] * NOTE_DISP - 1))
  130.                         break;
  131.                     if (note_volume[track][note_abs + i + 1] != 0)
  132.                         break;
  133.                 }
  134.                 switch (i) {
  135.                 case 0:
  136.                     break;
  137.                 case 1:
  138.                     fputs ("8", fp);
  139.                     break;
  140.                 case 2:
  141.                     fputs ("8.", fp);
  142.                     break;
  143.                 case 3:
  144.                     fputs ("4", fp);
  145.                     break;
  146.                 }
  147.                 note_abs += i;
  148.                 note_count += i;
  149. #endif
  150.             } else {
  151.                 fputs ("r", fp);
  152.             }
  153.             note_count++;
  154.             if (note_count >= 4) {
  155.                 note_count -= 4;
  156.                 fputs (" ", fp);    /* 16分音符4つごとに空白を入れる */
  157.                 note_count2++;
  158.                 if (note_count2 >= 4) {
  159.                     note_count2 -= 4;
  160.                     bar_count++;
  161.                     if (bar_count >= 2) {
  162.                         bar_count = 0;
  163.                         /* 2小節ごとに改行を入れる(最終小節でなければ) */
  164.                         if (note_abs < bar_max_table[bar_max] * NOTE_DISP - 1)
  165.                             fprintf (fp, "\n(t%d)\t\t", track + 9);
  166.                     } else {
  167.                         fputs ("   ", fp);    /* 4分音符4つごとに空白を入れる */
  168.                     }
  169.                 }
  170.             }
  171.         }
  172.         if (volume_current != 8)
  173.             fprintf (fp, "v8");
  174.         fprintf (fp, "\n(t%d)\t[loop]\n\n", track + 9);
  175.     }
  176.     fprintf (fp, "\n(p)\n");
  177.     fclose (fp);
  178.  
  179.     return (0);
  180. }
  181.  
  182.  
  183.  
  184. /*
  185.    .ZMS 解析:"(t9)" の場合
  186.    line_buffer に1行ぶんの .ZMS が入っているので、ヌル文字が現れるまで解析して
  187.    note_type[][], note_volume[][] に書き込む
  188.  */
  189. static void LoadZmsTrack (char *line_buffer, int track, int ct)
  190. {
  191.     char *p = line_buffer + ct;
  192.     unsigned char c;
  193.     int i;
  194.  
  195.     /* (t9) 行の行解析・桁ループ */
  196.     while (c = *p++) {
  197.         int eol_flag = 0;    /* 行解析終わり */
  198.  
  199.         if (isspace (c))
  200.             continue;    /* 空白は読み飛ばす */
  201.  
  202.         if (zms_analyse.note_no[track] >= BAR_MAX * NOTE_DISP)
  203.             break;    /* バッファがいっぱい */
  204.  
  205.         switch (c) {
  206.         case '/':
  207.             eol_flag = !0;    /* '/' が現れたら1行解析終わり */
  208.             break;
  209.  
  210.         case '[':
  211.             while ((c = *p++) && (c != ']'));    /* ']' まで読み飛ばす */
  212.             if (!c)
  213.                 eol_flag = !0;    /* 行末に達した */
  214.             break;
  215.  
  216.         case 'c':
  217.         case 'd':
  218.         case 'e':
  219.         case 'f':
  220.         case 'g':
  221.         case 'a':
  222.         case 'b':
  223.             note_volume[track][zms_analyse.note_no[track]]
  224.                 = zms_analyse.volume_current[track];
  225.             note_type[track][zms_analyse.note_no[track]] = c - 'c';
  226.             /* ここに break がない事に注意 */
  227.         case 'r':
  228.             /* 音階・休符の後の音長指定・16/8/8./4 のみ指定可能(弱い…) */
  229.             switch (*p) {
  230.             case '1':
  231.                 if (*(p + 1) == '6') {
  232.                     zms_analyse.note_no[track]++;    /* 16 */
  233.                     p += 2;        /* "16" の次を指すように */
  234.                 }
  235.                 break;
  236.             case '8':
  237.                 if (*(p + 1) == '.') {
  238.                     zms_analyse.note_no[track] += 3;    /* 8. */
  239.                     p += 2;        /* "8." の次を指すように */
  240.                 } else {
  241.                     zms_analyse.note_no[track] += 2;    /* 8 */
  242.                     p++;    /* "8" の次を指すように */
  243.                 }
  244.                 break;
  245.             case '4':
  246.                 zms_analyse.note_no[track] += 4;    /* 4 */
  247.                 p++;    /* "4" の次を指すように */
  248.                 break;
  249.             default:
  250.                 zms_analyse.note_no[track]++;    /* 16 */
  251.                 break;
  252.             }
  253.             break;
  254.  
  255.         case '~':
  256.             if (zms_analyse.volume_current[track] < 15)
  257.                 zms_analyse.volume_current[track]++;
  258.             break;
  259.  
  260.         case '_':
  261.             if (zms_analyse.volume_current[track] > 0)
  262.                 zms_analyse.volume_current[track]--;
  263.             break;
  264.  
  265.         case 'v':
  266.             i = 0;
  267.             while (isdigit (c = *p++)) {
  268.                 i *= 10;
  269.                 i += (c - '0');
  270.             }
  271.             p--;    /* 行きすぎたぶん */
  272.  
  273.             if ((i >= 0) && (i < 16))
  274.                 zms_analyse.volume_current[track] = i;
  275.             break;
  276.  
  277.         case 't':    /* テンポ変更 */
  278.             i = 0;
  279.             while (isdigit (c = *p++)) {
  280.                 i *= 10;
  281.                 i += (c - '0');
  282.             }
  283.             p--;    /* 行きすぎたぶん */
  284.  
  285.             note_tempo = 1;
  286.             while (i < VDISP60SEC / 4 / note_tempo)
  287.                 note_tempo++;
  288.             break;
  289.  
  290.         case '@':
  291.             p++;    /* @d などの d を読み飛ばす */
  292.             while (isdigit (c = *p++));    /* パラメーターを読み飛ばす */
  293.             p--;    /* 行きすぎたぶん */
  294.             break;
  295.  
  296.         default:
  297.             break;
  298.         }
  299.         if (eol_flag)
  300.             break;
  301.     }
  302. }
  303.  
  304.  
  305.  
  306. /*
  307.    .ZMS 解析:".o0c = fname.pcm" の場合
  308.    返り値
  309.    = 0:成功&致命的でないエラー(認識できない.ZMS)
  310.    < 0:エラー(.PCMが読み込めない)
  311.  */
  312. static int LoadZmsPcmAssign (char *line_buffer)
  313. {
  314.     int track, type;
  315.     char temp_fname[94];    /* .CNF に書かれていたファイル名 */
  316.     char full_fname[94];    /* フルパスに展開したファイル名 */
  317.     FILE *fp2;
  318.  
  319.     if (!isdigit (line_buffer[2]))
  320.         return (0);
  321.     track = line_buffer[2] - '0';
  322.     if (track > 7)
  323.         return (0);
  324.  
  325.     type = line_buffer[3] - 'c';
  326.     if ((type < 0) || (type > 3))
  327.         return (0);
  328.  
  329.     {
  330.         unsigned char *p = &line_buffer[4];
  331.         unsigned char *q = temp_fname;
  332.         int count = 0;
  333.         char c;
  334.  
  335.         /* 空白もしくは '=' を読み飛ばす */
  336.         while ((c = *p++) && (isspace (c) || (c == '=')));
  337.  
  338.         if (!c)        /* いきなり改行されてしまった? */
  339.             return (0);
  340.         --p;
  341.  
  342.         /* ファイル名をコピー */
  343.         while ((c = *q++ = *p++) && (!isspace (c)) && (count++ < 92));
  344.  
  345.         *--q = '\0';
  346.     }
  347.  
  348.     /* カレントディレクトリ、環境変数 zmusic,zmusic0~zmusic9 から .PCM ファイルを検索 */
  349.     if (!GetPcmPath (temp_fname, full_fname)) {
  350.         printf ("ファイル %s が読み込めません\n", temp_fname);
  351.         return (-1);
  352.     }
  353.     fp2 = fopen (full_fname, "rb");
  354.     if (fp2 == NULL) {
  355.         printf ("ファイル %s が読み込めません\n", temp_fname);
  356.         return (-1);
  357.     }
  358.     strcpy (&pcm_full_fname[type][track][0], temp_fname);
  359.  
  360.     /* 表示用ファイル名を取り出す */
  361.     {
  362.         char drive[4], dir[94], fname[23], ext[23];    /* パス名分解用 */
  363.         _splitpath (full_fname, drive, dir, fname, ext);
  364.         strcpy (pcm_fname[type][track], fname);
  365.         strcat (pcm_fname[type][track], ext);
  366.     }
  367.     fseek (fp2, 0, SEEK_END);
  368.     pcm_size[type][track] = ftell (fp2);
  369.     fseek (fp2, 0, SEEK_SET);
  370.  
  371.     if (pcm_ptr[type][track])    /* 既に確保されていれば */
  372.         free (pcm_ptr[type][track]);
  373.     pcm_ptr[type][track] = malloc (pcm_size[type][track]);
  374.     if (pcm_ptr[type][track] == NULL) {
  375.         printf ("PCM 用メモリが足りません\n");
  376.         fclose (fp2);
  377.         return (-1);
  378.     }
  379.     fread (pcm_ptr[type][track], pcm_size[type][track], 1, fp2);
  380.     fclose (fp2);
  381.  
  382.     return (0);
  383. }
  384.  
  385.  
  386.  
  387. /* .ZMS ファイル読み込み */
  388. int SoundLoadZms (char *fname)
  389. {
  390.     FILE *fp;
  391.     int track;
  392. #define LINE_BUFFER_SIZE    1024
  393.     char line_buffer[LINE_BUFFER_SIZE];
  394.     int last_track = -1;
  395.  
  396.     fp = fopen (fname, "r");
  397.     if (fp == NULL)
  398.         return (-1);
  399.  
  400.     /* .ZMS 解析用ワークの初期化 */
  401.     for (track = 0; track < TRACK_MAX; track++) {
  402.         zms_analyse.note_no[track] = 0;
  403.         zms_analyse.volume_current[track] = 8;
  404.         zms_analyse.l_current[track] = 0;
  405.     }
  406.  
  407.     /* .ZMSファイル解析・行ループ */
  408.     while (fgets (line_buffer, LINE_BUFFER_SIZE, fp)) {
  409.         switch (line_buffer[0]) {
  410.         case '.':
  411.             if ((line_buffer[1] == 'o') || (line_buffer[1] == 'O')) {
  412.                 if (LoadZmsPcmAssign (line_buffer) < 0) {
  413.                     fclose (fp);
  414.                     return (-1);
  415.                 }
  416.             }
  417.             break;
  418.  
  419.         case '(':
  420.             switch (line_buffer[1]) {
  421.             case 't':    /* (t9) など */
  422.                 {
  423.                     int track;
  424.                     int ct;        /* 何文字目から解析するか */
  425.                     if (!isdigit (line_buffer[2]))
  426.                         break;
  427.                     track = line_buffer[2] - '0';
  428.                     if (isdigit (line_buffer[3])) {
  429.                         track = track * 10 + (line_buffer[3] - '0');
  430.                         if (line_buffer[4] != ')')
  431.                             break;
  432.                         ct = 5;
  433.                     } else {
  434.                         if (line_buffer[3] != ')')
  435.                             break;
  436.                         ct = 4;
  437.                     }
  438.                     track -= 9;    /* (t9)~(t16) を track0~7 にする */
  439.                     if ((track >= 0) && (track < 8)) {
  440.                         LoadZmsTrack (line_buffer, track, ct);
  441.                         last_track = track;
  442.                     }
  443.                 }
  444.                 break;
  445.             default:
  446.                 break;
  447.             }
  448.             break;
  449.  
  450.         case '\t':    /* (t9) が省略された時 */
  451.             if (last_track >= 0)
  452.                 LoadZmsTrack (line_buffer, last_track, 1);
  453.             break;
  454.  
  455.         default:
  456.             break;
  457.         }
  458.     }
  459.     fclose (fp);
  460.  
  461.     /* 小節数を求める */
  462.     bar_max = 0;
  463.     for (track = 0; track < TRACK_MAX; track++) {
  464.         int i;
  465.         for (i = 0; i < BAR_MAX_TABLE; i++) {
  466.             /* 使われている音符数を調べてその最大値に合わせる */
  467.             if (zms_analyse.note_no[track] > (bar_max_table[i] * NOTE_DISP)) {
  468.                 if (bar_max < i + 1)
  469.                     bar_max = i + 1;
  470.             }
  471.         }
  472.     }
  473.  
  474.     return (0);
  475. }
  476.  
  477.  
  478.  
  479. /* 起動時に1回だけ呼ばれる */
  480. int SoundInit0 (char *fname)
  481. {
  482.     int track, type;
  483.  
  484.     for (type = 0; type < TYPE_MAX; type++) {
  485.         for (track = 0; track < TRACK_MAX; track++) {
  486.             pcm_fname[type][track][0] = '\0';
  487.             pcm_ptr[type][track] = NULL;
  488.         }
  489.     }
  490.  
  491.     return (0);
  492. }
  493.  
  494.  
  495.  
  496. /* PCM を鳴らす */
  497. void SoundPcm8Out (int track, int type, int volume)
  498. {
  499.     /* 一応存在するかチェック */
  500.     if (pcm_ptr[type][track])
  501.         Pcm8Play (track, (volume << 16) + 0x0403,
  502.               pcm_ptr[type][track], pcm_size[type][track]);
  503. }
  504.  
  505.  
  506.  
  507. /* 終了時に1回だけ呼ばれる */
  508. void SoundTini0 (void)
  509. {
  510.     int track, type;
  511.  
  512.     for (type = 0; type < TYPE_MAX; type++) {
  513.         for (track = 0; track < TRACK_MAX; track++) {
  514.             if (pcm_ptr[type][track])    /* 既に確保されていれば */
  515.                 free (pcm_ptr[type][track]);
  516.         }
  517.     }
  518. }
  519.